/*
*	Final executable file. 
*	CS 505 - Computer Structures
*	Milestone - 2 ==> Implementation of Tomasulo algorithm
*	Author:: Shyam (shyam2347@gmail.com)
*
*	Input : Trace File from PIN
*	Output : CPI (Cycles per Instruction value)
*/

#include <stdio.h>
#include <stdlib.h>
#include "global.h"
#include "queue.h"
#include "instructionFetch.c"
#include "hazard.c"

int main(int argc, char *argv[])
{
	//Trace file should be passed as command line argument
	if(argc != 2)
	{
		printf("USAGE:: %s <filename>\n",argv[0]);
		exit(1);
	}

	//Open the tracefile
	FILE *fp = fopen(argv[1],"r");
	if(fp == NULL)
	{
		printf("File does not exist\n");
		exit(1);
	}

	//Variable declarations
	int f_flag = 0;
	int d_flag = 0;
	int is_flag = 0;
	int r_flag = 0;
	int ex_flag = 0;
	int c_flag = 0;

	int f_busy = 0;
	int d_busy = 0;
	int is_busy = 0;
	int r_busy = 0;
	int c_busy = 0;
	int a1_busy = 0;
	int a2_busy = 0;
	int div_busy = 0;
	int mul_busy = 0;
	int def_busy = 0;
	int load_busy = 0;
	int store_busy = 0;

	int f_start = 0;
	int d_start = 0;
	int is_start = 0;
	int r_start = 0;
	int c_start = 0;
	int a1_start = 0;
	int a2_start = 0;
	int div_start = 0;
	int mul_start = 0;
	int def_start = 0;

	int f_cycle = 0;
	int d_cycle = 0;
	int is_cycle = 0;
	int r_cycle = 0;
	int c_cycle = 0;
	int a1_cycle = 0;
	int a2_cycle = 0;
	int div_cycle = 0;
	int def_cycle = 0;
	int mul_cycle = 0;
	int load_cycle = 0;
	int store_cycle = 0;

	int load_depend = 0;
	int store_depend = 0;
	
	int rf_read = 0;

	ins *instr = NULL;
	ins instr1;
	ins instr_d;
	ins instr_is;
	ins instr_ex;
	ins instr_add1;
	ins instr_add2;
	ins instr_default;
	ins instr_mul;
	ins instr_div;
	ins instr_rob;
	ins instr_load;
	ins instr_store;
	ins instr_storepre;

	//I use this branch flag here to stop instruction fetch..
	int ins_b_flag = 0;
	unsigned long long ins_b_count = 0;

	unsigned long long instr_count = 0;
	unsigned long long cycle = 0;

	int if_current_size_prev = IF_CURRENT_SIZE;
	int id_current_size_prev = ID_CURRENT_SIZE;
	int is_current_size_prev = IS_CURRENT_SIZE;
	int rob_current_size_prev = ROB_CURRENT_SIZE;
	int adder1_current_size_prev = ADDER1_CURRENT_SIZE;
	int adder2_current_size_prev = ADDER2_CURRENT_SIZE;
	int loader_current_size_prev = LOADER_CURRENT_SIZE;
	int store_current_size_prev = STORE_CURRENT_SIZE;
	int multiplier_current_size_prev = MULTIPLIER_CURRENT_SIZE;
	int divider_current_size_prev = DIVIDER_CURRENT_SIZE;
	int default_current_size_prev = DEFAULT_CURRENT_SIZE;

	//Initializing all the queues
	init_queue();
	initregfile();
	
	// 1 Golden rule I will follow here, each iteration of the loop will do 1 cycle work only.. 
	while(1) //This loop will contain stages of pipeline
	{
		//Instruction Fetch 
		if( f_cycle == IF_CYCLE )
		{
			f_cycle = 0;
			f_busy = 0;

			//enqueue the instruction fetched & increment the buffer size..
			instr_count++;
			instr1.inscounter = instr_count;
			my_enqueue(instr1,IF_QUEUE);
			IF_CURRENT_SIZE++;
			printf("Fetch complete : %lld\n",cycle);
			//printf("Fetch countx : %lld\n",instr_count);
		}	
		if( f_flag == 0 && ins_b_flag == 0)
		{
			if( f_busy == 0)
			{
				if(IF_CURRENT_SIZE < IF_BUFFERLIMIT)
				{
					instr = (struct instruction*) malloc(sizeof(struct instruction));
					int fetchReturn = -7; //Need to store something other than -1 and 0, I am storing my fav #
					while( fetchReturn != 1 && fetchReturn != 0 )
					{
						//Pass filepointer and fetch one instruction.				
						fetchReturn = instruction_fetch(fp, instr);
						if ( fetchReturn == 1 )
						{
							//In this stage, we will read only the instruction and the address
							strcpy(instr1.s_instruction, instr->s_instruction);
							strcpy(instr1.address, instr->address);
							instr1.INSC.rmax = instr->INSC.rmax;
							instr1.INSC.wmax = instr->INSC.wmax;
							instr1.INSC.memcount = instr->INSC.memcount;

							//Setting default values..
							instr1.rob_entry_unique = -1;
							instr1.ins_type = 0;
							instr1.ins_b = 0;
							instr1.ins_ex_complete = 0;
							instr1.ins_exception = 0;
							instr1.load_store = 0;
							instr1.reg1 = 0;
							instr1.reg2 = 0;
							instr1.reg3 = 0;
							instr1.reg4 = 0;
							instr1.reg5 = 0;
							instr1.reg6 = 0;
							instr1.reg7 = 0;
							instr1.reg8 = 0;
							instr1.add2 = 0;
							instr1.add_op1 = 0;
							instr1.add_op2 = 0;
							instr1.mul_op1 = 0;
							instr1.mul_op2 = 0;
							instr1.a_load = 0;
					
							f_cycle = 1;
							f_busy = 1;
							f_flag = 0;
						}
						else if( fetchReturn == 0 )
						{
							//printf("End of instructions\n");
							f_flag = 1;
						}
						//These are lines which does not contain instruction
						//else
						//	printf("Not an instruction\n");
					}
					free(instr);
				}
			}
			else if(f_busy == 1)
			{
				f_cycle++;
			}
		}

		//Instruction Decode
		//Instruction type is found and updated during d_enqueue stage..
		//Given that ID takes 1 cycle and RF read takes another cycle. If any is required, d_busy is set to 1..
		if( d_busy == 0 )
		{
			//if( (ID_CURRENT_SIZE < ID_BUFFERLIMIT) && ( (IF_CURRENT_SIZE-1 > 0) || (f_flag == 1) ))
			if( (ID_CURRENT_SIZE < ID_BUFFERLIMIT) && (if_current_size_prev > 0) )
			{
				//if(IF_CURRENT_SIZE != 0)
				if(if_current_size_prev > 0)
				{
					//Dequeue from IF & Enqueue to ID
					instr_d = my_dequeue(IF_QUEUE);
					IF_CURRENT_SIZE--;

					// I should check what kind of instruction it is and add it into my ins
					// I do that part in enqueue.. #queue.c
		
					// Here goes the decode stage functionality.. 

					// get Operands
					get_insbreakdown(instr_d.s_instruction, instr_d.mnemonic, instr_d.operand1, instr_d.operand2, instr_d.operand3, 
							instr_d.operand4, instr_d.operand5);
					get_insreg(instr_d.mnemonic, instr_d.operand1, instr_d.operand2, instr_d.operand3, instr_d.operand4, instr_d.operand5, 
							instr_d.creg1, &instr_d.reg1, instr_d.creg2, &instr_d.reg2, instr_d.creg3, &instr_d.reg3, instr_d.creg4, 
							&instr_d.reg4, instr_d.creg5, &instr_d.reg5, instr_d.creg6, &instr_d.reg6, instr_d.creg7, &instr_d.reg7, 
							instr_d.creg8, &instr_d.reg8);

					// How will I find the same for mov or add when I have direct address or immediate operands..
					// Better way is to move this part of code inside get_insreg function.. 
					if (strcmp(instr_d.mnemonic,"pop") == 0 || strcmp(instr_d.mnemonic,"popf") == 0)
					{
						if(instr_d.reg1 == 1)
							instr_d.reg1 = 2;
					}

					if(instr_d.reg1 == 1 || instr_d.reg1 == 2)
						regfile_insert(instr_d.creg1, instr_d.inscounter);
					if(instr_d.reg2 == 1 || instr_d.reg2 == 2)
						regfile_insert(instr_d.creg2, instr_d.inscounter);
					if(instr_d.reg3 == 1 || instr_d.reg3 == 2)
						regfile_insert(instr_d.creg3, instr_d.inscounter);
					if(instr_d.reg4 == 1 || instr_d.reg4 == 2)
						regfile_insert(instr_d.creg4, instr_d.inscounter);
					if(instr_d.reg5 == 1 || instr_d.reg5 == 2)
						regfile_insert(instr_d.creg5, instr_d.inscounter);
					if(instr_d.reg6 == 1 || instr_d.reg6 == 2)
						regfile_insert(instr_d.creg6, instr_d.inscounter);
					if(instr_d.reg7 == 1 || instr_d.reg7 == 2)
						regfile_insert(instr_d.creg7, instr_d.inscounter);
					if(instr_d.reg8 == 1 || instr_d.reg8 == 2)
						regfile_insert(instr_d.creg8, instr_d.inscounter);

					//printf("Mnemonic : %s\t", instr_d.mnemonic);
					//printf("Operand 1 : %s\t", instr_d.operand1);
					//printf("Operand 2 : %s\t", instr_d.operand2);

					// As I add the instruction into ID Queue, I also need to do one thing..
					// point f) in the doc.. Check if its a branch instruction and stop IF till PC is computed..
					// I have to find mnemonic here.. check if it is a branch..
					if( getInsBranch(instr_d.mnemonic) == 1 )
					{
						ins_b_flag = 1;
						ins_b_count = instr_d.inscounter;
					}

	
					// Check if instn is a load / store..
					if( (strcmp(instr_d.mnemonic,"push") == 0) || (strcmp(instr_d.mnemonic,"pushf") == 0) )
					{
						instr_d.load_store = 2;
					}
					else if((strcmp(instr_d.mnemonic, "pop") == 0) || (strcmp(instr_d.mnemonic, "popf") == 0) || 
						(strcmp(instr_d.mnemonic,"lea") == 0) || (strcmp(instr_d.mnemonic,"lds") == 0) || 
						(strcmp(instr_d.mnemonic,"les") == 0) || (strcmp(instr_d.mnemonic,"lfs") == 0) || 
						(strcmp(instr_d.mnemonic,"lgs") == 0) || (strcmp(instr_d.mnemonic,"lss") == 0) || 
						(strcmp(instr_d.mnemonic,"fld") == 0) || (strcmp(instr_d.mnemonic,"fst") == 0) || 
						(strcmp(instr_d.mnemonic,"lahf") == 0))
					{
						instr_d.load_store = 1;
					}
					else if((strcmp(instr_d.mnemonic,"mov") == 0)  || (strcmp(instr_d.mnemonic,"movzx") == 0) || 
						(strcmp(instr_d.mnemonic,"cmovz") == 0) || (strcmp(instr_d.mnemonic,"movsd") == 0) || 
						(strcmp(instr_d.mnemonic,"xchg") == 0) || (strcmp(instr_d.mnemonic,"movsw") == 0))
					{
						//logic to find if it has braces to find if it is load / store..
						if( (strrchr(instr_d.operand1, '[') != NULL) && (strrchr(instr_d.operand1,']') != NULL) )
						{
							get_addpresent(instr_d.operand1,&instr_d.add_op1);
							get_mulpresent(instr_d.operand1,&instr_d.mul_op1);
							instr_d.load_store = 2;
						}
						if( (strrchr(instr_d.operand2, '[') != NULL) && (strrchr(instr_d.operand2,']') != NULL) )
						{
							get_addpresent(instr_d.operand2,&instr_d.add_op2);
							get_mulpresent(instr_d.operand2,&instr_d.mul_op2);
							if(instr_d.load_store == 2)
								instr_d.load_store = 3;
							else
								instr_d.load_store = 1;
						}
					}

					// Printing this to check if error occurs..
					if( instr_d.load_store != 0 && instr_d.load_store != 1 && instr_d.load_store != 2 && instr_d.load_store != 3)
					{
						printf("Mnemonic : %s\t", instr_d.mnemonic);
						printf("Operand 1 : %s\t", instr_d.operand1);
						printf("Operand 2 : %s\t", instr_d.operand2);
						printf("\nThis should not happen\n");
					}

					// Finding if instruction requires RF read.
					if(instr_d.INSC.rmax + instr_d.INSC.wmax > 0)
						rf_read = 1;
					if(rf_read == 0)
					{
						my_enqueue(instr_d,ID_QUEUE);
						ID_CURRENT_SIZE++;
						printf("Decode complete : %lld\n",cycle);
						d_flag = 0;
					}
					else
						d_busy = 1;
				}
				else
				{
					d_flag = 1;
				}
			}
		}
		else
		{
			// As RF read also takes one cycle only, I just complete it.. 
			// This does not look like a parameterizable value, so I dont do things in a generic way
			d_busy = 0;
			rf_read = 0;
			my_enqueue(instr_d,ID_QUEUE);
			ID_CURRENT_SIZE++;
			printf("Decode complete : %lld\n",cycle);
			d_flag = 0;
		}
	
		// Execute - Tomasulo engine.. 
		// 1)Issue
		// What will I do here..? Check Issue Buffer Size and ROB buffer size, if allowed bring instruction from IDQ to here..
		// Check if reservation station are free and then push the ins to FU.. along with the ins, i will add ROB entry #, 
		// so I can update the ROB entry after completion.. pushing instruction to FU need not be in order.. 
		// May be I can push the pushing instruction work to Execute.. This is a design issue which I can change if my prediction sucks as usual.
		if( (IS_CURRENT_SIZE < IS_BUFFERLIMIT) && (ROB_CURRENT_SIZE < ROB_BUFFERLIMIT) )
		{
			//Dequeue from IDQ.. Enqueue ISQ & ROB..
			//if(ID_CURRENT_SIZE != 0)
			if(id_current_size_prev > 0)
			{
				instr_is = my_dequeue(ID_QUEUE);
				ID_CURRENT_SIZE--;

				instr_is.rob_entry_unique = my_enqueue(instr_is,ROB_QUEUE);
				ROB_CURRENT_SIZE++;

				my_enqueue(instr_is,IS_QUEUE);
				IS_CURRENT_SIZE++;
				printf("Issue complete : %lld\n",cycle);

				is_flag = 0;
			}
			else
			{
				is_flag = 1;
			}
		}

		// 2)Execute
		// I should have functionality for each FU.. Fuck, its 2:17am but this is the most crunchy part, I want to do it... 
		// Read each entry in ISQ.. push it to execute if there are no hazards and res. station has space.. Now I will consider only res. station space..
		// Lets ignore the hazards and just implement the funcitonality..
		// Hazards will be taken care here.. Only if there are no hazards the ins is pushed into reservation stations..
		// I will have many stations.. 2 for adder, 1 for divide, 1 for multiplier, other default
		//if( IS_CURRENT_SIZE != 0 )
		if( is_current_size_prev > 0 )
		{
			instr_ex = is_getlastins();
			printf("Type : %d\n",instr_ex.ins_type);
			switch(instr_ex.ins_type)
			{
				case FU_ADDER:
						if(ADDER1_CURRENT_SIZE < RESSTATION_ADDER1)
						{
							instr_ex = my_dequeue(IS_QUEUE);
							IS_CURRENT_SIZE--;
							my_enqueue(instr_ex,ADDER1_QUEUE);
							ADDER1_CURRENT_SIZE++;
						}
						else if(ADDER2_CURRENT_SIZE < RESSTATION_ADDER2)
						{
							instr_ex = my_dequeue(IS_QUEUE);
							IS_CURRENT_SIZE--;
							my_enqueue(instr_ex,ADDER2_QUEUE);
							ADDER2_CURRENT_SIZE++;
						}
						break;
				case FU_MULTIPLIER:
						if( MULTIPLIER_CURRENT_SIZE < RESSTATION_MULTIPLIER)
						{
							printf("I am in multiplier\n");
							instr_ex = my_dequeue(IS_QUEUE);
							IS_CURRENT_SIZE--;
							my_enqueue(instr_ex,MULTIPLIER_QUEUE);
							MULTIPLIER_CURRENT_SIZE++;
						}
						break;
				case FU_DIVIDER:
						if( DIVIDER_CURRENT_SIZE < RESSTATION_DIVIDER)
						{
							instr_ex = my_dequeue(IS_QUEUE);
							IS_CURRENT_SIZE--;
							my_enqueue(instr_ex,DIVIDER_QUEUE);
							DIVIDER_CURRENT_SIZE++;
						}	
						break;
				case FU_LOADSTORE:
						if(instr_ex.load_store == 0 )
						{
							if(DEFAULT_CURRENT_SIZE < RESSTATION_DEFAULT)
                                                	{
                                                        	instr_ex = my_dequeue(IS_QUEUE);
                                                        	IS_CURRENT_SIZE--;
                                                        	my_enqueue(instr_ex,DEFAULT_QUEUE);
                                                        	DEFAULT_CURRENT_SIZE++;
                                                	}
						}
						else if(instr_ex.load_store == 1)
						{
							if(LOADER_CURRENT_SIZE < RESSTATION_LOADER)
							{
                                                        	instr_ex = my_dequeue(IS_QUEUE);
                                                        	IS_CURRENT_SIZE--;
                                                        	my_enqueue(instr_ex,LOADER_QUEUE);
                                                        	LOADER_CURRENT_SIZE++;
							}
						}		
						else if(instr_ex.load_store == 2)
						{
							if(STORE_PRE_CURRENT_SIZE < RESSTATION_STORE)
							{
								instr_ex = my_dequeue(IS_QUEUE);
								IS_CURRENT_SIZE--;
								my_enqueue(instr_ex,STORE_PREQUEUE);
								STORE_PRE_CURRENT_SIZE++;	
							}	
						}
						else if(instr_ex.load_store == 3)
						{
                                                        if(LOADER_CURRENT_SIZE < RESSTATION_LOADER && STORE_PRE_CURRENT_SIZE < RESSTATION_STORE)
                                                        {
                                                                instr_ex = my_dequeue(IS_QUEUE);
                                                                IS_CURRENT_SIZE--;
                                                                my_enqueue(instr_ex,LOADER_QUEUE);
                                                                LOADER_CURRENT_SIZE++;
                                                                my_enqueue(instr_ex,STORE_PREQUEUE);
                                                                STORE_PRE_CURRENT_SIZE++;
                                                        }
						}
						else
							printf("erroroneous loadtype\n");
						break;
				case FU_LOGICAL:
						//As per description, only one of the adder will handle branch calculation stuff.. So, I will assume ADDER2 will do it.
						if( ADDER2_CURRENT_SIZE < RESSTATION_ADDER2)
						{
							instr_ex = my_dequeue(IS_QUEUE);
							IS_CURRENT_SIZE--;
							my_enqueue(instr_ex,ADDER2_QUEUE);
							ADDER2_CURRENT_SIZE++;
						}
						break;
				default:
						if( DEFAULT_CURRENT_SIZE < RESSTATION_DEFAULT)
						{
							instr_ex = my_dequeue(IS_QUEUE);
							IS_CURRENT_SIZE--;
							my_enqueue(instr_ex,DEFAULT_QUEUE);
							DEFAULT_CURRENT_SIZE++;
						}
			}
		}

		//ADDEr1
		if( a1_cycle+1 == ADDER_CYCLE )
		{
			a1_cycle = 0;
			a1_busy = 0;
			ADDER1_CURRENT_SIZE--;
			printf("Adder1 complete : %lld\n",cycle);
			// For branch.. there is a logic here..
			// I am checking if the instruction has a branch.. then am checking if that is the last branch instruction found by decode..
			// If so, then unblock the fetch instruction, else there is still some another instruction in the pipeline which has branch 
			// fetch will resume only after that completes execution..
			// Looks like a neat idea.. 
			if( (instr_add1.ins_b == 1) && (instr_add1.inscounter = ins_b_count) )
			{
				ins_b_flag = 0;
			}

			//Now, I need to update ins_complete variable.. How do I do it?
			//I dequeued from adder1 and is but I will have it in rob..
			//So, I will search the ins in rob, and update its value.?
			//Ok done.. For now, I will do this.. Later worry if this is the best method.. Ok.. going to queue.c to add functionality for ins complete
			//printf("Rob entry : %d\n", instr_add1.rob_entry_unique);
			if( instr_add1.load_store == 1 )
			{
				load_depend = 0;
			}
			else if (instr_add1.load_store == 2)
			{
                                store_depend = 0;
			}
			else if(instr_add1.load_store == 3 && instr_add1.a_load == 1)
                        {
                                 store_depend = 0;
                        }
			else if(instr_add1.load_store == 3)
                        {
				load_depend = 0;
                        }
			else
			{
				if( ins_complete(instr_add1.rob_entry_unique) != 1)
				{
					printf("Error in completion - Adder1\n");
					exit(1);
				}
				removebusy_writereg(instr_add1);
			}
		}
		if(a1_busy == 0)
		{
			if( ADDER1_CURRENT_SIZE > 0 )
			{
				instr_add1 = adder1_getlastins();
				//printf("Stuck here %s\n",instr_add1.s_instruction);
				if(ins_executeorstall(instr_add1) == 1)
				{
					instr_add1 = my_dequeue(ADDER1_QUEUE);
					if( instr_add1.load_store != 1 && instr_add1.load_store != 2 && instr_add1.load_store != 3)
						removebusy_readreg(instr_add1);
					a1_busy = 1;
					a1_cycle = 1;
				}
			}
		}
		else
		{
			a1_cycle++;
		}

		//Adder2
		if( a2_cycle+1 == ADDER_CYCLE)
		{
			a2_cycle = 0;
			a2_busy = 0;
			ADDER2_CURRENT_SIZE--;
			printf("Adder2 complete : %lld\n",cycle);
			if( (instr_add2.ins_b == 1) && (instr_add2.inscounter = ins_b_count) )
			{
				ins_b_flag = 0;
			}

			if(instr_add2.load_store == 1)
                        {
				load_depend = 0;
                        }
			else if (instr_add2.load_store == 2)
                        {
				store_depend = 0;
                        }
			else if(instr_add2.load_store == 3 && instr_add2.a_load == 1)
			{
				store_depend = 0;
			}
			else if(instr_add2.load_store == 3)
                        {
				load_depend = 0;
                        }
			else
			{
				if( ins_complete(instr_add2.rob_entry_unique) != 1)
				{
					printf("Error in completion - Adder2\n");
					exit(1);
				}
				removebusy_writereg(instr_add2);
			}
		}
		if(a2_busy == 0)
		{
			if( ADDER2_CURRENT_SIZE > 0 )
			{
				instr_add2 = adder2_getlastins();
				if(ins_executeorstall(instr_add2) == 1)
				{
					instr_add2 = my_dequeue(ADDER2_QUEUE);
					if( instr_add2.load_store != 1 && instr_add2.load_store != 2 && instr_add2.load_store != 3)
						removebusy_readreg(instr_add2);
					a2_busy = 1;
					a2_cycle = 1;
				}
			}
		}
		else
		{
			a2_cycle++;
		}

		//Multiplier
		if(mul_cycle == MULTIPLIER_CYCLE)
		{
			mul_cycle = 0;
			mul_busy = 0;
			MULTIPLIER_CURRENT_SIZE--;
			printf("Multiplier complete : %lld\n",cycle);
			if(instr_mul.load_store == 1)
                        {
				load_depend = 0;
			}
			else if (instr_mul.load_store == 2)
                        {
				store_depend = 0;
                        }
			else if (instr_mul.load_store == 3 && instr_mul.a_load == 1)
			{
                                 store_depend = 0;
			}
			else if(instr_mul.load_store == 3)
                        {
                                load_depend = 0;
                        }
			else
			{
				if( ins_complete(instr_mul.rob_entry_unique) != 1)
				{
					printf("Error in completion - Multiplier\n");
					exit(1);
				}
				removebusy_writereg(instr_mul);
			}
		}
		if(mul_busy == 0)
		{
			if( MULTIPLIER_CURRENT_SIZE > 0 )
			{
				printf("Multiplier start : %lld\n",cycle);
				instr_mul = multiplier_getlastins();
				if(ins_executeorstall(instr_mul) == 1)
				{
				printf("Multiplier start 1 : %lld\n",cycle);
					instr_mul = my_dequeue(MULTIPLIER_QUEUE);
					if( instr_mul.load_store != 1 && instr_mul.load_store != 2 && instr_mul.load_store != 3)
						removebusy_readreg(instr_mul);
					mul_busy = 1;
					mul_cycle = 1;
				}
			}
		}
		else
		{
			printf("Multiplier else cycle : %lld\n",cycle);
			mul_cycle++;
		}

		//Divider
		if(div_cycle == DIVIDER_CYCLE)
		{
			div_cycle = 0;
			div_busy = 0;
			DIVIDER_CURRENT_SIZE--;
			printf("Divider complete: %lld\n",cycle);
			if( ins_complete(instr_div.rob_entry_unique) != 1)
			{
				printf("Error in completion - Divider\n");
				exit(1);
			}
			removebusy_writereg(instr_div);
		}
		if(div_busy == 0)
		{
			if( DIVIDER_CURRENT_SIZE > 0 )
			{
				instr_div = divider_getlastins();
				if(ins_executeorstall(instr_div) == 1)
				{
					instr_div = my_dequeue(DIVIDER_QUEUE);
					removebusy_readreg(instr_div);
					div_busy = 1;
					div_cycle = 1;
				}
			}
		}
		else
		{
			div_cycle++;
		}
	
		//Default
		if(def_cycle == DEFAULT_CYCLE)
		{
			def_cycle = 0;
			def_busy = 0;
			DEFAULT_CURRENT_SIZE--;
			printf("Default complete: %lld\n",cycle);
			if( ins_complete(instr_default.rob_entry_unique) != 1)
			{
				printf("Error in completion - Default\n");
				exit(1);
			}	
			//printf("Default\n");
			removebusy_writereg(instr_default);
		}
		if(def_busy == 0)
		{
			if( DEFAULT_CURRENT_SIZE > 0 )
			{
				instr_default = default_getlastins();
				if(ins_executeorstall(instr_default) == 1)
				{
					instr_default = my_dequeue(DEFAULT_QUEUE);
					removebusy_readreg(instr_default);
					def_cycle = 1;
					def_busy = 1;
				}
			}
		}	
		else
		{
			def_cycle++;
		}


		//Load
		if(load_depend == 0)
		{

		if (load_cycle+1 == LOAD_CYCLE)
		{
                        load_cycle = 0;
                        load_busy = 0;
                        LOADER_CURRENT_SIZE--;
			printf("Loader complete: %lld\n",cycle);
			if(instr_load.load_store == 3)
                        {
				instr_load.a_load = 1;
				//Set the storepre also to a_load = 1
				storep_setaload(instr_load.inscounter);	
			}
			else
			{
                        	if( ins_complete(instr_load.rob_entry_unique) != 1)
                        	{
                                	printf("Error in completion - load\n");
                                	exit(1);
                        	}
				if(instr_load.load_store == 1)
					removebusy_writereg(instr_load);
			}
			//printf("Load complete %lld\n",cycle);
                }
                if(load_busy == 0)
                {
                        if( LOADER_CURRENT_SIZE > 0 )
                        {
				instr_load = load_getlastins();
			/*	if(instr_load.add_op2 != 0)
                                {
                                	if(ADDER1_CURRENT_SIZE < RESSTATION_ADDER1)
                                        {
						load_decaddop2();
                                                my_enqueue(instr_load,ADDER1_QUEUE);
                                                ADDER1_CURRENT_SIZE++;
						load_depend = 1;
                                        }
                                        else if(ADDER2_CURRENT_SIZE < RESSTATION_ADDER2)
                                        {
						load_decaddop2();
                                                my_enqueue(instr_load,ADDER2_QUEUE);
                                                ADDER2_CURRENT_SIZE++;
						load_depend = 1;
                                        }
                                }
                                else if(instr_load.mul_op2 != 0)
                                {
                                	if( MULTIPLIER_CURRENT_SIZE < RESSTATION_MULTIPLIER)
                                        {
						load_decmulop2();
                                                my_enqueue(instr_load,MULTIPLIER_QUEUE);
                                                MULTIPLIER_CURRENT_SIZE++;
						load_depend = 1;
                                        }
                                }*/
				//else
				{
					if(ins_executeorstall_load(instr_load) == 1)
					{
                                		instr_load = my_dequeue(LOADER_QUEUE);
						removebusy_readreg(instr_load);
                                		load_cycle = 1;
                                		load_busy = 1;
					}
				}
                        }
                }
                else
                {
                        load_cycle++;
                }
	
		}

		//Store Pre
		if(store_depend == 0)
		{
			if(STORE_PRE_CURRENT_SIZE > 0)
			{
				instr_storepre = storepre_getlastins();
				if(instr_storepre.load_store == 2 || ( instr_storepre.load_store == 3 && instr_storepre.a_load == 1) )
				{
				/*if(instr_storepre.add_op1 != 0)
                                {
                                	if(ADDER1_CURRENT_SIZE < RESSTATION_ADDER1)
                                        {
				printf("Inside store pre %s\n",instr_storepre.s_instruction);
				printf(" pre %d\n",check_regbusy(instr_storepre.creg1));
				printf(" pre %d\n",check_regbusy(instr_storepre.creg2));
                                        	storep_decaddop1();
                                                my_enqueue(instr_storepre,ADDER1_QUEUE);
                                                ADDER1_CURRENT_SIZE++;
						store_depend = 1;
                                        }
                                        else if(ADDER2_CURRENT_SIZE < RESSTATION_ADDER2)
                                        {
                                                storep_decaddop1();
                                                my_enqueue(instr_storepre,ADDER2_QUEUE);
                                                ADDER2_CURRENT_SIZE++;
						store_depend = 1;
                                        }
                                }
                                else if(instr_storepre.mul_op1 != 0)
                                {
                                	if( MULTIPLIER_CURRENT_SIZE < RESSTATION_MULTIPLIER)
                                        {
                                        	storep_decmulop1();
                                                my_enqueue(instr_storepre,MULTIPLIER_QUEUE);
                                                MULTIPLIER_CURRENT_SIZE++;
						store_depend = 1;
                                        }
                                }*/
                                //else
                                {
                                        instr_storepre = my_dequeue(STORE_PREQUEUE);
                                        STORE_PRE_CURRENT_SIZE--;
					if( ins_complete(instr_storepre.rob_entry_unique) != 1)
                                	{
						printf("Error in completion - Store Pre\n");
						exit(1);
                                	}
                                }
				}
			}
		}


		//Store
                if(store_cycle+1 == STORE_CYCLE)
                {
                        store_cycle = 0;
                        store_busy = 0;
                        STORE_CURRENT_SIZE--;
			printf("Store complete: %lld\n",cycle);
			instr_rob = my_dequeue(ROB_QUEUE);
			removebusy_writereg(instr_rob);
			ROB_CURRENT_SIZE--;
			//printf("Store complete %lld\n",cycle);
                }
                if(store_busy == 0)
                {
                        if( STORE_CURRENT_SIZE > 0 )
                        {
				instr_store = store_getlastins();
				//printf("Wait for store\n");
				if(ins_executeorstall_store(instr_store) == 1)
				{
                                	instr_store = my_dequeue(STORE_QUEUE);
					removebusy_readreg(instr_store);
                               		store_cycle = 1;
                                	store_busy = 1;
				}	
                        }
                }
                else
                {
                        store_cycle++;
                }


		if( (ADDER1_CURRENT_SIZE == 0) && (ADDER2_CURRENT_SIZE == 0) && (DIVIDER_CURRENT_SIZE == 0) && (DEFAULT_CURRENT_SIZE == 0) && (MULTIPLIER_CURRENT_SIZE == 0) )
		{
			ex_flag = 1;
		}
		else
		{
			ex_flag = 0;
		}

		//3)Complete .. Why am I writing so much of comments as if someone is going to read it..? better implement the functionality asshole..

		//ROB Entry & commit..
		// Check if the ins @ head has an exception flag.. if so flush the rest of rob.. or else commit the instruction..
		// But first, check if there is anything in ROB..
		if( ROB_CURRENT_SIZE > 0 )
		{
			r_flag = 0;
			if( rob_lastins_complete() == 1 )
			{
				if( rob_lastins_loadstore() == 2 || rob_lastins_loadstore() == 3 )
				{
					printf("Rob store : %lld\n",cycle);
					rob_setlastinsincomplete();
					instr_rob = rob_getlastins();
					my_enqueue(instr_rob,STORE_QUEUE);
					STORE_CURRENT_SIZE++;
				}
				else
				{
					instr_rob = my_dequeue(ROB_QUEUE);
					ROB_CURRENT_SIZE--;
					//do commit of instruction.. I dunno how to do though.. :(
					//Diff instruction have diff ways.. I think I should update the reg file regarding this..
					//Load n store will have different techniques..
				}
			}
		}
		if( ROB_CURRENT_SIZE > 0 )
		{
			r_flag = 0;
			if( rob_lastins_exception() == 1 )
			{
				rob_flush();
				ROB_CURRENT_SIZE = 0;
			}
		}
		if( ROB_CURRENT_SIZE == 0 )
		{
			//printf("ROb current size == 0 %lld\n",cycle);
			r_flag = 1;
		}

		//Commit - why did I put commmit again.. dunno, I will figure it out at the end..
		
		/*	
		printf("f_flag %d\n",f_flag);
		printf("d_flag %d\n",d_flag);
		printf("is_flag %d\n",is_flag);
		printf("ex_flag %d\n",ex_flag);
		*/

		//if( (f_flag == 1) && (d_flag == 1) && (is_flag == 1) && (ex_flag == 1) && (r_flag == 1) )
		if( (f_flag == 1) && (IF_CURRENT_SIZE == 0) && (d_busy == 0) && (ID_CURRENT_SIZE == 0) && (IS_CURRENT_SIZE == 0) && (ROB_CURRENT_SIZE == 0) && (r_flag == 1) )
		{
			break;
		}

		//Increment cycle
		cycle++;
		if_current_size_prev = IF_CURRENT_SIZE;
		id_current_size_prev = ID_CURRENT_SIZE;
		is_current_size_prev = IS_CURRENT_SIZE;
		rob_current_size_prev = ROB_CURRENT_SIZE;
		adder1_current_size_prev = ADDER1_CURRENT_SIZE;
		adder2_current_size_prev = ADDER2_CURRENT_SIZE;
		loader_current_size_prev = LOADER_CURRENT_SIZE;
		store_current_size_prev = STORE_CURRENT_SIZE;
		multiplier_current_size_prev = MULTIPLIER_CURRENT_SIZE;
		divider_current_size_prev = DIVIDER_CURRENT_SIZE;
		default_current_size_prev = DEFAULT_CURRENT_SIZE;
	}
	printf("Total # of cycles:: %lld\n", cycle);
	printf("Total # of instructions:: %lld\n", instr_count);
	printf("CPI = %f\n", (float)cycle/instr_count);
	fclose(fp);
	return 0;
}
